package com.ply.flashsalessystem.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ply.flashsalessystem.entity.PaymentBO;
import com.ply.flashsalessystem.entity.pojo.*;
import com.ply.flashsalessystem.entity.status.GoodsPutAwayStatus;
import com.ply.flashsalessystem.entity.status.OrderStatus;
import com.ply.flashsalessystem.entity.status.ReturnOrderStatus;
import com.ply.flashsalessystem.entity.vo.store.OrderForStoreVo;
import com.ply.flashsalessystem.entity.vo.user.ShopCarForGoodsVo;
import com.ply.flashsalessystem.entity.wrapper.GoodsWrapper;
import com.ply.flashsalessystem.entity.wrapper.ShopCarWrapper;
import com.ply.flashsalessystem.entity.wrapper.UserWrapper;
import com.ply.flashsalessystem.entity.wrapper.WrapperOrder;
import com.ply.flashsalessystem.exception.GoodsException;
import com.ply.flashsalessystem.exception.OrderException;
import com.ply.flashsalessystem.mapper.ShopCarMapper;
import com.ply.flashsalessystem.mapper.UserMapper;
import com.ply.flashsalessystem.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ply.flashsalessystem.utils.ALiPayUtil;
import com.ply.flashsalessystem.utils.RuleUtils;
import com.ply.flashsalessystem.utils.UserUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author XiaoPan
 * @since 2022-03-23
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    final
    UserMapper userMapper;

    final
    GoodsService goodsService;

    final
    ShopCarService shopCarService;

    final
    OrderForGoodsService orderForGoodsService;

    final
    StoreService storeService;

    final
    UserAmountService userAmountService;

    final
    OrderForGoodsDetaileService orderForGoodsDetaileService;

    final
    ReturnOfGoodsService returnOfGoodsService;

    @Autowired
    ShopCarMapper shopCarMapper;

    @Autowired
    ReturnOfGoodsDetailsService returnOfGoodsDetailsService;

    @Autowired
    ALiPayUtil aLiPayUtil;


    public UserServiceImpl(UserMapper userMapper, GoodsService goodsService, ShopCarService shopCarService, OrderForGoodsService orderForGoodsService, StoreService storeService, UserAmountService userAmountService, OrderForGoodsDetaileService orderForGoodsDetaileService, ReturnOfGoodsService returnOfGoodsService) {
        this.userMapper = userMapper;
        this.goodsService = goodsService;
        this.shopCarService = shopCarService;
        this.orderForGoodsService = orderForGoodsService;
        this.storeService = storeService;
        this.userAmountService = userAmountService;
        this.orderForGoodsDetaileService = orderForGoodsDetaileService;
        this.returnOfGoodsService = returnOfGoodsService;
    }


    /**
     * 用户注册
     *
     * @param user user对象
     * @return 注册成功是否
     * name iphone pwd
     */
    @Override
    public boolean addUser(User user) {
        //使用 敏感词 过滤 name 使用正则 匹配 name iphone
        //正则匹配 用户名 name 电话 以及 密码
        if (RuleUtils.userName(user.getUserName())
                || RuleUtils.iphonePattern(user.getIphone())
                || RuleUtils.pwdPattern(user.getPwd())
        ) {
            return false;
        }
        //todo 敏感词 过滤

        // 判断 用户 name , iphone 是否存在
        if (queryUserByName(user.getUserName()) != null || queryUserByIphone(user.getIphone()) != null) {
            return false;
        }
        return userMapper.insert(user) != 0;
    }

    /**
     * 修改密码
     *
     * @param oldPwd 原先密码
     * @param newPwd 新密码
     * @return 修改成功是否
     */

    @Override
    public boolean updatePwd(String oldPwd, String newPwd) {
        User user = userMapper.selectById(UserUtils.getUserId());
        if (user.getPwd().equals(oldPwd)) {
            user.setPwd(newPwd);
            return userMapper.updateById(user) != 0;
        }
        return false;
    }

    /**
     * 修改默认地址    name    iphone  头像avatar
     *
     * @param user 新的用户信息
     * @return 修改成功是否
     * <p>
     * 需要 保证 name 不 重复
     * 需要 保证 iphone 不 重复
     * //todo 优化 修改 信息 应该 分开来 要不然 每次都查询一次  每个修改都有单独的接口
     */
    @Override
    public boolean updateUser(User user) {
        //todo 头像 路径 没有解决
        User user1 = queryUserByName(user.getUserName());
        // 保证 name 不重复
        if (user1 != null && Objects.equals(user1.getUserId(), user.getUserId())) {
            throw new RuntimeException("用户名重复");
        }

        User user2 = queryUserByIphone(user.getIphone());
        //保证 iphone 不重复
        if (user2 != null && Objects.equals(user2.getUserId(), user.getUserId())) {
            throw new RuntimeException("iphone重复");
        }

        // name 和 iphone的 规则 如果修改了的话 name iphone
        if (!RuleUtils.userName(user.getUserName())) {
            throw new RuntimeException(RuleUtils.nameError);
        }
        if (!RuleUtils.iphonePattern(user.getIphone())) {
            throw new RuntimeException(RuleUtils.iphoneError);
        }
        if (!RuleUtils.pwdPattern(user.getPwd())) {
            throw new RuntimeException(RuleUtils.pwdError);
        }
        user.setUserId(UserUtils.getUserId());
        User user3 = userMapper.selectById(UserUtils.getUserId());
        user3.setUserName(user.getUserName());
        user3.setPwd(user.getPwd());
        user3.setIphone(user.getIphone());
        log.debug("{}",user);
        return userMapper.updateById(user3) != 0;
    }

//    /**
//     * 条件 分页查询 用户 只会给管理员看的吧
//     *
//     * @param current     当前页
//     * @param limit       每页的个数
//     * @param userWrapper 条件
//     * @return 返回的数据  需要对 其处理
//     */
//    @Override
//    public Page<User> getUserToStore(Integer current, Integer limit, UserWrapper userWrapper) {
//        userWrapper.setStoreId(UserUtils.getUserId());
//        return getUserAll(current, limit, userWrapper);
//    }


    /**
     * 查询自己的信息
     *
     * @param id 用户id  一般从 工具类中取
     * @return 返回 user 的所有信息
     * <p>
     * id 要正确  不然会 空指针   管理员 可以查询
     */
    //todo 可以 抛出异常
    @Override
    public User getUser(long id) {
        return userMapper.selectById(id);
    }

//    @Override
//    public Page<Goods> getGoodsPage(Integer current, Integer limit, GoodsWrapper goodsWrapper) {
//        return null;
//    }

    /**
     * 条件 分页查询 商品
     *
     * @param current      当前页
     * @param limit        每页的个数
     * @param goodsWrapper 商品条件
     * @return 返回的数据  需要对 其处理
     * 用户 商品要上架 的才能查询
     */
//    @Override
//    public Page<Goods> getGoodsPage(Integer current, Integer limit, GoodsWrapper goodsWrapper) {
//        goodsWrapper.setPutAway(GoodsPutAwayStatus.DO_AWAY);
//        return goodsService.queryGoodsAll(current, limit, goodsWrapper);
//    }


    /**
     * 添加商品 到 购物车
     *
     * @param goodsId   商品id
     * @param goodsNums 商品数量
     * @return 添加成功是否
     * <p>
     * 注:
     * 需要判断 购物车 中 是否 有该物品
     * 想要添加进购物车  先查询 goods 的 余量 看看 是否可以添加  不够 返回 false
     * 还有商品的 起售 情况
     */
    @Override
    @Transactional
    public boolean addShopCar(Integer goodsId, double goodsNums) {
        log.info("service开始 添加到购物车 商品id{}  数量:{}  ", goodsId, goodsNums);
        Goods goods = goodsService.getById(goodsId);

        if (goods == null) {
            throw new GoodsException(" goodsId 错误");
        }
        if (goods.getMinSales() > goodsNums) {
            throw new GoodsException(" 无法加入 购物车 没有达到 最少售卖量");
        }

        // 商品上架了才能 加入 购物车
        if (!Objects.equals(goods.getPutAway(), GoodsPutAwayStatus.DO_AWAY)) {
            throw new GoodsException(" goodsId 为未上架");
        }
        // 查询goods的 余量
        if (goods.getRemainNums() < goodsNums) {
            throw new GoodsException("商品 余量不足");
        }
        // 查询购物车中 我 是否 有 该商品
        // todo 有问题
//        ShopCarWrapper shopCarWrapper = new ShopCarWrapper();
//        shopCarWrapper.setUserId(UserUtils.getUserId());
//        shopCarWrapper.setName(goods.getName());
//        Page<ShopCarForGoodsVo> goodsOfShopCar = shopCarService.getGoodsOfShopCar(-1, -1, shopCarWrapper);

        QueryWrapper<ShopCar> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", UserUtils.getUserId());
        queryWrapper.eq("goods_id", goodsId);
        ShopCar shopCar = shopCarService.getOne(queryWrapper);

        // 购物车 中 有 该 商品
        if (shopCar == null) {
            // 增加 购物车
            boolean b = shopCarService.addShopCar(goodsId, goodsNums);
            log.info("购物车 新增成功");
            return b;
        }
        shopCar.setGoodsNum(shopCar.getGoodsNum() + goodsNums);
        shopCarService.updateById(shopCar);
        log.info("购物车 增加 数量成功 ");
        return true;

    }

    /**
     * 将商品从 购物车 中删除
     *
     * @param shopCarId 购物车id
     * @return 删除成功与否
     * <p>
     * 注: 在购物车中 还需 有一个 方法 将 所有物品 清空 的 方法 便于 用户
     */
    @Override
    public boolean deleteGoodsInShopCar(Integer shopCarId) {
        //需要购物车id 存在
        return shopCarService.removeById(shopCarId);
    }

    /**
     * 分页条件查询购物车
     *
     * @param current        当前页
     * @param limit          每页的个数
     * @param shopCarWrapper 购物车条件
     * @return 返回购物车中的商品
     */
    @Override
    public Page<ShopCarForGoodsVo> getGoodsOfShopCar(Integer current, Integer limit, ShopCarWrapper shopCarWrapper) {
        shopCarWrapper.setUserId(UserUtils.getUserId());
        return shopCarService.getGoodsOfShopCar(current, limit, shopCarWrapper);
    }

    /**
     * 生成订单
     *
     * @param storeId 店家id 用于 获取地址
     * @return 是否成功
     * <p>
     * 清除购物车
     * 新建order orderDetails (判断 用户是否 有未支付 的订单)
     */
    @Override
    @Transactional
    public boolean createOrder(Long storeId, List<ShopCar> list) {
        // 判断 用户 是否 有未在支付的订单
        if (!isNoPayOrder()) {
            log.debug("用户有未支付的 订单 不允许 新建订单");
            return false;
        }

        //商品 数量相应 剪掉 即将商品 锁起来
        for (ShopCar shopCar : list) {
            Integer goodsId = shopCar.getGoodsId();
            Double goodsNum = shopCar.getGoodsNum();
            Goods byId = goodsService.getById(goodsId);

            //判断 商品数量 是不是超过 最少售卖 量
            if (byId.getMinSales() > goodsNum) {
                throw new GoodsException("商品 最少售卖量没有达到");
            }
            goodsNum = byId.getRemainNums() - goodsNum;
            if (goodsNum < 0) {
                throw new GoodsException("商品剩余量不足, 请重新下订单");
            }
            if (!goodsService.updateGoodsNums(goodsId, goodsNum)) {
                throw new GoodsException("更新商品数量 失败");
            }
        }

        // 清除购物车
        for (ShopCar shopCar : list) {
//            shopCarService.removeById(shopCar);
            if (!shopCarMapper.deleteByShopCarId(shopCar.getShopCarId())) {
                throw new RuntimeException("删除购物车失败");
            }
        }

        //生成orderForGoods 对象 生成对象
        orderForGoodsService.createOrder(storeId, list);
        return true;
    }

    /**
     * 分页 条件 查询 获取 用户订单
     *
     * @return 订单详情信息
     * <p>
     * 注 :   不可以 在一个订单 未支付的情况下 在创建 另一个订单
     */
    @Override
    @Transactional
    public Page<OrderForStoreVo> getOrder(Integer current,
                                          Integer limit,
                                          WrapperOrder wrapperOrder) {
        wrapperOrder.setUserId(UserUtils.getUserId());
        return orderForGoodsService.queryOrder(current, limit, wrapperOrder);
    }

    /**
     * 为订单 付款
     *
     * @param ofgID 订单 id
     * @return 付款成功与否  以后会对接 微信 支付宝 会修改
     */
    @Override
    @Transactional
    public String payForOrder(Integer ofgID) {
        log.info("进入 UserService 中 的 payForOrder 参数 ofgId:{}", ofgID);
        // 1    查询 该订单 的 金额
        OrderForGoods orderForGoods = orderForGoodsService.getById(ofgID);

        if (orderForGoods == null) {
            throw new OrderException("找不到 该订单");
        }
        // 这个订单状态是什么 前提: 订单状态未支付
        if (!Objects.equals(orderForGoods.getStatus(), OrderStatus.NO_PAY)) {
            throw new OrderException("这个订单的状态为 {} +" + orderForGoods.getStatus() + ", 不可以在 付款");
        }

        //优先使用 账户余额付款  todo 没有写完
        User user = getUser(orderForGoods.getUserId());
//        User user = getUser(11);
        Double balanceMoney = user.getBalanceMoney();

        //需要付款的金额为
        //todo 调用 接口付款
        if (balanceMoney < orderForGoods.getAmountDue()) {
            Integer ofgId = orderForGoods.getOfgId();
            double v = orderForGoods.getAmountDue() - balanceMoney;
            String title = "生鲜水果";
            try {
                return aLiPayUtil.pay(ofgId, v, title);
            } catch (Exception e) {
                throw new RuntimeException("支付失败");
            }
        } else {
            //直接 余额支付
            balanceMoney = orderForGoods.getAmountDue() - balanceMoney;
        }
        user.setBalanceMoney(balanceMoney);
        //修改用户 账户
        userMapper.updateById(user);

        // 付款后 修改订单 状态 增加流水记录
        orderForGoods.setStatus(OrderStatus.DO_PAY);
//        orderForGoodsService.updateOrder(ofgID,OrderStatus.DO_PAY);
        if (!orderForGoodsService.statusToDoPay(ofgID)) {
            throw new RuntimeException("已付款不允许在付款");
        }
        //增加流水记录
        UserAmount userAmount = new UserAmount();
        userAmount.setUserId(orderForGoods.getUserId());
        userAmount.setAmount(orderForGoods.getAmountDue());
        userAmountService.save(userAmount);
        log.info("进入 UserService 中 的 payForOrder 结束");
        return "ok";
    }

    /**
     * 查询 所有 用户的 所有信息
     */
    @Override
    public Page<User> getUserAll(Integer current, Integer limit, UserWrapper userWrapper) {
        return userMapper.getUserAll(new Page<>(current, limit), userWrapper);
    }


    /**
     * 用户确认 收货
     *
     * @param ofgID 订单 id
     *              <p>
     *              注: 需要判断 订单状态 只有 小店签收 后  才开始  进入 用户签收  默认两天后自动签收
     */
    @Override
    @Transactional
    public boolean confirmationOfReceiptForUser(Integer ofgID) {
        OrderForGoods orderForGoods = orderForGoodsService.getById(ofgID);
        // 查询 是用户自己的 订单 存在 并且 订单状态 是 店家已签收
        if (orderForGoods == null
                || !Objects.equals(orderForGoods.getStatus(), OrderStatus.STORE_DO_SIGN)
                || !orderForGoods.getUserId().equals(UserUtils.getUserId())
        ) {
            throw new OrderException("订单状态异常");
        }
//        return orderForGoodsService.updateOrder(ofgID,OrderStatus.USER_DO_SIGN);
        return orderForGoodsService.statusToUserDoSign(ofgID);
    }


    /**
     * 退单申请
     * 感觉不适合放在这里    还有多个订单详情id 一起退货     什么时候才可 申请退货呢?  在签收后才可以退货
     * 申请退单 参数: 订单id, 订单详情id, 申请退单数量, 退单留言 message 可以null,
     *
     * @param orgId   订单id
     * @param orgDId  订单详情id
     * @param nums    申请退单数量
     * @param message 退单留言
     */
    @Override
    public boolean requestReturnOrder(Integer orgId, Integer orgDId, double nums, String message) {
        //判断这个订单是不是属于操作用户的
        OrderForGoods byId = orderForGoodsService.getById(orgId);
        if (!Objects.equals(byId.getUserId(), UserUtils.getUserId())) {
            log.debug("退单申请失败, 该订单:{},不属于用户:{}", orgId, UserUtils.getUserId());
            return false;
        }
        //判断订单状态  只有签收完了之后 才可以退货 只有状态为 买家已签收 才可以退货
        if (!Objects.equals(byId.getStatus(), OrderStatus.USER_DO_SIGN)) {
            log.debug("退单申请失败, 订单只有在用户已签收的情况下才可以退货");
            return false;
        }
        //判断 这个订单详情是不是属于 这个订单 的
        OrderForGoodsDetaile byId1 = orderForGoodsDetaileService.getById(orgDId);
        if (!Objects.equals(byId1.getOfgId(), orgId)) {
            log.debug("退单申请失败, 该订单详情:{},不属于订单:{}", orgDId, orgId);
            return false;
        }
        //判断订单数量
        if (nums <= 0 || nums > byId1.getGoodsRealNums()) {
            log.debug("申请退单数量:{},实际订单数量:{}", nums, byId1.getGoodsRealNums());
            return false;
        }


        double price = byId1.getAmountDue() / byId1.getGoodsOrderNums();
        //申请退单成功  创建退单表  创建退货详情单
        return returnOfGoodsService.requestReturnOrder(orgId, orgDId, price, nums, message);
    }

    /**
     * 退单 对一个订单 退多个详情
     *
     * @param orgId 订单id
     * @param list  退单详情
     * @return
     */

    @Override
    public boolean requestReturnOrderMany(Integer orgId, List<ReturnOfGoodsDetails> list) {
        //判断这个订单是不是属于操作用户的
        OrderForGoods byId = orderForGoodsService.getById(orgId);
        if (!Objects.equals(byId.getUserId(), UserUtils.getUserId())) {
            log.debug("退单申请失败, 该订单:{},不属于用户:{}", orgId, UserUtils.getUserId());
            return false;
        }
        //判断订单状态  只有签收完了之后 才可以退货 只有状态为 买家已签收 才可以退货
        if (!Objects.equals(byId.getStatus(), OrderStatus.USER_DO_SIGN)) {
            log.debug("退单申请失败, 订单只有在用户已签收的情况下才可以退货");
            return false;
        }

        //判断这些订单详情id  是不是属于 该订单的
        QueryWrapper<OrderForGoodsDetaile> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("ofg_id", orgId);
        List<OrderForGoodsDetaile> list1 = orderForGoodsDetaileService.list(queryWrapper);
        int i = 0;
        for (OrderForGoodsDetaile orderForGoodsDetaile : list1) {
            for (ReturnOfGoodsDetails returnOfGoodsDetails : list) {
                //
                if (Objects.equals(orderForGoodsDetaile.getOrgDId(), returnOfGoodsDetails.getOrgDId())) {
//                    int reOrderNum = 0;
                    // 如果 有 这个订单已经发生过了退单 则不允许再次发生 退单请求
                    Integer orgDId = orderForGoodsDetaile.getOrgDId();
                    QueryWrapper<ReturnOfGoodsDetails> queryWrapper1 = new QueryWrapper<>();
                    queryWrapper1.eq("org_d_id", orgDId);
                    List<ReturnOfGoodsDetails> list2 = returnOfGoodsDetailsService.list(queryWrapper1);
                    for (ReturnOfGoodsDetails ofGoodsDetails : list2) {
                        if (Objects.equals(ofGoodsDetails.getStatus(), ReturnOrderStatus.APPLYING)
                                || Objects.equals(ofGoodsDetails.getStatus(), ReturnOrderStatus.COMPLETE)) {
                            throw new OrderException("该订单已经发生了退单 不允许 再次发生 退单");
                        }
                    }
                    i++;
                    //退单数量
                    double nums = returnOfGoodsDetails.getNums();
                    //订单数量
                    double goodsRealNums = orderForGoodsDetaile.getGoodsRealNums();
                    if (nums > goodsRealNums) {
                        //如果退单数量大于订单数量 错误
                        throw new OrderException("申请退单数量" + nums + ",实际订单数量:" + goodsRealNums);
                    }
                    returnOfGoodsDetails.setPrice(orderForGoodsDetaile.getAmountDue() / orderForGoodsDetaile.getGoodsOrderNums());
                    returnOfGoodsDetails.setAmount(returnOfGoodsDetails.getPrice() * nums);
                }
            }
        }
        // 判断 退单的所有id 都对的上  订单详情id
        if (i != list.size()) {
            throw new OrderException("错误 参数错误");
        }
        // 新增
        returnOfGoodsService.requestReturnOrderMan(orgId, list);
        return true;
    }


    /**
     * 通过name 查询
     */
    private User queryUserByName(String name) {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper
                .eq("user_name", name);

        return userMapper.selectOne(userQueryWrapper);
    }

    /**
     * 通过iphone 查询
     */
    private User queryUserByIphone(String iphone) {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper
                .eq("iphone", iphone);
        return userMapper.selectOne(userQueryWrapper);
    }

    /**
     * 判断用户 是否 有 未支付的 订单
     *
     * @return
     */
    private boolean isNoPayOrder() {
        //判断用户是否有未支付的 订单
        QueryWrapper<OrderForGoods> goodsQueryWrapper = new QueryWrapper<>();
        goodsQueryWrapper.eq("user_id", UserUtils.getUserId());
        goodsQueryWrapper.eq("status", OrderStatus.NO_PAY);
        List<OrderForGoods> list1 = orderForGoodsService.list(goodsQueryWrapper);
        //如果有未支付的订单 则需要先支付 或者 取消订单
        if (!list1.isEmpty()) {
            log.info("有未支付的订单");
            return false;
        }
        return true;
    }
}
